from mcp.server.fastmcp import FastMCP
import httpx


# 美国国家气象局 (NWS) API 的基础 URL
NWS_API_BASE = "https://api.weather.gov"
# 设置请求头中的 User-Agent
USER_AGENT = "weather-app/1.0"

# 初始化 MCP 服务器
mcp = FastMCP("weather")


async def make_nws_request(url):
    """
    通用的异步函数，用于向 NWS API 发起请求。

    Args:
        url (str): 请求的完整 URL

    Returns:
        dict[str, Any] | None: 成功时返回 JSON 字典，失败时返回 None。
    """
    # 设置 header 头信息
    headers = {
        "User-Agent": USER_AGENT,
        "Accept": "application/geo+json"
    }
    # 执行异步 HTTP GET 请求
    async with httpx.AsyncClient() as client:
        try:
            # 发起请求
            response = await client.get(url, headers=headers, timeout=30)
            # 若响应码为 4xx 或 5xx，则引发异常
            response.raise_for_status()
            # 请求成功则返回
            return response.json()
        except Exception:
            return None


def format_alert(feature):
    """
    格式化天气预警的 JSON 数据。
    """
    props = feature["properties"]
    return f"""
        事件: {props.get('event', '未知')}
        区域: {props.get('areaDesc', '未知')}
        严重性: {props.get('severity', '未知')}
        描述: {props.get('description', '无描述信息')}
        指令: {props.get('instruction', '无具体指令')}
    """


@mcp.tool()
async def get_alerts(state):
    """
    获取美国某个州当前生效的天气预警信息。
    @mcp.tool(): 表示该方法可以被大模型作为工具调用。

    Args:
        state (str): 两个字母的美国州代码（如 CA、NY 等）。
    """
    # 发起请求
    url = f"{NWS_API_BASE}/alerts/active/area/{state}"
    data = await make_nws_request(url)
    # 健壮性检查
    if not data or "features" not in data:
        return "无法获取预警信息或未找到相关数据！"
    # 无预警情况
    if not data["features"]:
        return "该州当前没有生效的天气预警！"
    # 有预警情况
    alerts = [format_alert(feature) for feature in data["features"]]
    return "\n---\n".join(alerts)


@mcp.tool()
async def get_forecast(latitude, longitude):
    """
    根据经纬度获取天气预报。
    @mcp.tool(): 表示该方法可以被大模型作为工具调用。

    Args:
        latitude (float): 纬度。
        longitude (float): 经度。
    """
    # 根据经纬度获取包含具体预报接口 URL 的网格点信息
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)
    if not points_data:
        return "无法获取该地点的预报数据！"
    # 提取实际的天气预报接口 URL 并请求数据
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)
    if not forecast_data:
        return "无法获取详细的预报信息！"
    # 提取预报周期数据
    forecasts = []
    periods = forecast_data["properties"]["periods"]
    for period in periods[:5]:
        forecast = f"""
            {period['name']}:
            温度: {period['temperature']}°{period['temperatureUnit']}
            风力: {period['windSpeed']} {period['windDirection']}
            预报: {period['detailedForecast']}
        """
        forecasts.append(forecast)
    return "\n---\n".join(forecasts)


if __name__ == "__main__":
    # 服务器启动
    # transport="stdio"：表示服务器将通过标准输入/输出（stdin/stdout）与客户端（如大模型）进行通信
    mcp.run(transport="stdio")